/**********************************************************************
* Filename: Cliente.java
* Created: 2013/05/31
* @author Fernando Brito e Abreu
**********************************************************************/
package org.quasar.airNova.businessLayer;

import org.quasar.airNova.persistenceLayer.Database;

import java.util.Set;
import java.util.HashSet;

public abstract class Cliente{
	
	/***********************************************************
	* @return all instances of class Cliente
	***********************************************************/
	public static Set<Cliente> allInstancesAbstract(){
		return Database.allInstances(Cliente.class);
	}
	
	private int codigo_cliente;
	private String morada;
	private int n_contribuinte;
	private String nome;
	
	/**********************************************************************
	* Default constructor
	**********************************************************************/
	public Cliente(){
	}
	
	/**********************************************************************
	* Parameterized constructor
	* @param codigo_cliente the codigo_cliente to initialize
	* @param morada the morada to initialize
	* @param n_contribuinte the n_contribuinte to initialize
	* @param nome the nome to initialize
	**********************************************************************/
	public Cliente(int codigo_cliente, String morada, int n_contribuinte, String nome){
		this.codigo_cliente = codigo_cliente;
		this.morada = morada;
		this.n_contribuinte = n_contribuinte;
		this.nome = nome;
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the codigo_cliente of the cliente
	**********************************************************************/
	public int codigo_cliente(){
		return codigo_cliente;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param codigo_cliente the codigo_cliente to set
	**********************************************************************/
	public void setCodigo_cliente(int codigo_cliente){
		this.codigo_cliente = codigo_cliente;
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the morada of the cliente
	**********************************************************************/
	public String morada(){
		return morada;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param morada the morada to set
	**********************************************************************/
	public void setMorada(String morada)
	{
		this.morada = morada;
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the n_contribuinte of the cliente
	**********************************************************************/
	public int n_contribuinte()
	{
		return n_contribuinte;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param n_contribuinte the n_contribuinte to set
	**********************************************************************/
	public void setN_contribuinte(int n_contribuinte)
	{
		this.n_contribuinte = n_contribuinte;
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the nome of the cliente
	**********************************************************************/
	public String nome()
	{
		return nome;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param nome the nome to set
	**********************************************************************/
	public void setNome(String nome)
	{
		this.nome = nome;
	}
	
	/**********************************************************************
	* ONE2MANY getter for Cliente[1] <-> CartaoCredito[*]
	* @return the cartoes of the possuidor
	**********************************************************************/
	public Set<CartaoCredito> cartoes()
	{
		Set<CartaoCredito> result = new HashSet<CartaoCredito>();
		for (CartaoCredito x : CartaoCredito.allInstances())
			if (x.possuidor()  ==  this)
				result.add(x);
		return result;
	}
	
	/**********************************************************************
	* ONE2MANY multiple setter for Cliente[1] <-> CartaoCredito[*]
	* @param cartoes the cartoes to set
	**********************************************************************/
	public void setCartoes(Set<CartaoCredito> cartoes)
	{
		for (CartaoCredito x : cartoes)
			x.setPossuidor(this);
	}
	
	/**********************************************************************
	* ONE2MANY single setter for Cliente[1] <-> CartaoCredito[*]
	* @param cartaocredito the cartaocredito to add
	**********************************************************************/
	public void addCartoes(CartaoCredito cartaocredito)
	{
		cartaocredito.setPossuidor(this);
	}
	
	/**********************************************************************
	* ONE2MANY getter for Cliente[1] <-> Reserva[*]
	* @return the reservas of the cliente
	**********************************************************************/
	public Set<Reserva> reservas()
	{
		Set<Reserva> result = new HashSet<Reserva>();
		for (Reserva x : Reserva.allInstances())
			if (x.cliente()  ==  this)
				result.add(x);
		return result;
	}
	
	/**********************************************************************
	* ONE2MANY multiple setter for Cliente[1] <-> Reserva[*]
	* @param reservas the reservas to set
	**********************************************************************/
	public void setReservas(Set<Reserva> reservas)
	{
		for (Reserva x : reservas)
			x.setCliente(this);
	}
	
	/**********************************************************************
	* ONE2MANY single setter for Cliente[1] <-> Reserva[*]
	* @param reserva the reserva to add
	**********************************************************************/
	public void addReservas(Reserva reserva)
	{
		reserva.setCliente(this);
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	* @param r the r to set
	**********************************************************************/
	public void efectuar_pagamento(Reserva r){
		Set<Reserva> sr = reservas();
		
		for(Reserva reserva: sr){
			if(reserva.n_reserva() == r.n_reserva()){
				reserva.setPagamento(EstadoPagamento.efectuado);
				Database.update(reserva);
				return;
			}
		}
		
	}
	
	//	PRE-CONDITIONS (TODO)
	/*
	pre CartaoTemDeEstarValido
		self.reservas->select(rs : Reserva | (rs.n_reserva = r.n_reserva))->collectNested($e : Reserva | $e.bilhetes)->flatten->forAll(b : Bilhete | b.realizacao.ocorre_em.isBefore(self.reservas->select(rs : Reserva | (rs.n_reserva = r.n_reserva))->asSequence->first.cartaoCredito.data_expira))
	
	pre EstadoTemDeSerPendente
		(self.reservas->select(rs : Reserva | (rs.n_reserva = r.n_reserva))->asSequence->first.pagamento = EstadoPagamento::pendente)
	
	*/
	
	//	POST-CONDITIONS (TODO)
	/*
	post PagamentoEfectuado
		(self.reservas->select(rs : Reserva | (rs.n_reserva = r.n_reserva))->asSequence->first.pagamento = EstadoPagamento::efectuado)
	
	*/
	
	/**********************************************************************
	* Object serializer
	**********************************************************************/
	public String toString()
	{
		return "Cliente [codigo_cliente=" + codigo_cliente + ", morada=" + morada + ", n_contribuinte=" + n_contribuinte + ", nome=" + nome + "]";
	}
	
}
